
package com.bitland.demo.microservice1.aspect;

import com.bitland.demo.microservice1.annotation.MyTestAnnotation;
import java.lang.reflect.Method;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

//@Aspect注解： 作用是表明这是一个切面类，springBoot便会将 MyTestAnnotationAspect 类实现为切面类。
@Aspect
@Component
@Slf4j
public class MyTestAnnotationAspect {
    //private static final Logger log = LoggerFactory.getLogger(MyTestAnnotationAspect.class);

    public MyTestAnnotationAspect() {
    }
    /**
     * 切面类与注解定义类的关联关系
     * 要对哪些类中的哪些方法进行增强，进行切割，指的是被增强的方法。即要切哪些东西。
     */
    @Pointcut("@annotation(com.bitland.demo.microservice1.annotation.MyTestAnnotation)")
    private void MyTest() {
    }

    /**
     * spring aop的切面编程为我们提供了四种切入的时机，在执行方法前，在执行方法后，在方法报出异常后，还有环绕方法执行。
     * 这在切面编程里的术语称之为通知，也就是我们上面说的how，在什么时候通知切面类执行切面方法。
     * 这四个时机spring aop提供了四个注解来支持，也就是 @Before , @After , @AfterThrowing , @Around 。
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("MyTest()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method targetMethod = methodSignature.getMethod();
        log.info("---------------------------> 测试自定义注解开始!");
        if (targetMethod.isAnnotationPresent(MyTestAnnotation.class)) {
            MyTestAnnotation myTestAnnotation = (MyTestAnnotation)targetMethod.getAnnotation(MyTestAnnotation.class);
            //前面的代码只为取到 使用注解时，传入的value 值
            String value = myTestAnnotation.value();
            log.info("------------------------> 注解值!  " + value);
        }

        /**
         * @Before在切片方法对象实际调用前执行。
         * @Around 可以调用 joinPoint.proceed()实际执行切片对象方法。
         * @After方法在@Around方法之后调用。
         * 注意，如果在Around中不调用joinPoint.proceed()，则@Before注解的方法不会调用，但是@After还是会调用。
         */

        log.info("------------------------> 1");
        //执行被加注解方法
        Object obj = proceedingJoinPoint.proceed();
        log.info("------------------------> 3");
        return obj;
    }
}
